﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;


namespace Comm.Security
{
    /// <summary>
    /// 服务器自动生成客户端许可文件
    /// </summary>
    public class ServerLicense
    {

        private XDocument xDoc = null;

        const string CONST_LICENSE_FILENAME = "ServerLicense.dat";
        /// <summary>
        /// 授权文件路径
        /// </summary>
        private string fileDir = "";

        /// <summary>
        /// 许可总数量(如果许可数量为-1表示无客户端限制)
        /// </summary>
        private int Count = 0;

        /// <summary>
        /// 许可有效天数（如果为-1则永久许可）
        /// </summary>
        private int Days = 0;

        /// <summary>
        /// 服务器许可授权时间
        /// </summary>
        private DateTime LicenseDate = DateTime.Now;

        /// <summary>
        /// 许可PCSN列表
        /// </summary>
        private List<string> ListLicenseSn;

        private ServerLicense()
        {

        }

        private ServerLicense(XDocument xdoc, string dir)
        {
            xDoc = xdoc;

            fileDir = dir;

            ListLicenseSn = new List<string>();
            try
            {
                Count = int.Parse(getData(xDoc, "Count"));

                Days = int.Parse(getData(xDoc, "LicenseDays"));

                LicenseDate = DateTime.Parse(getData(xDoc, "LicenseDate"));

                ListLicenseSn.AddRange(xDoc.Descendants("Client").Select((xe) => xe.Value));

            }
            catch (Exception e)
            {
                throw e;
            }

        }
        /// <summary>
        /// 创建客户端授权文件
        /// </summary>
        /// <param name="Sn"></param>
        /// <returns></returns>
        public byte[] CreateLicenseFile(string Sn)
        {
            if (!ListLicenseSn.Exists((s) => s == Sn))
            {
                if (Count != -1 && ListLicenseSn.Count >= Count) return new byte[0];

                ListLicenseSn.Add(Sn);
                if (xDoc.Descendants("Licenses").Count() == 0)
                {
                    xDoc.Element("ServerLicense").Add(new XElement("Licenses"));
                }

                xDoc.Descendants("Licenses").First().Add(new XElement("Client", Sn));

                Save(xDoc, string.Format(@"{0}\{1}", fileDir, CONST_LICENSE_FILENAME));
            }

            int day = 0;

            if (Days == -1)
            {
                day = -1;
            }
            else if (Days - Math.Abs(DateTime.Now.Subtract(LicenseDate).Days) > 0)
            {
                day = Days - Math.Abs(DateTime.Now.Subtract(LicenseDate).Days);
            }
            else
            {
                //如果剩余为天数为0，则返回空字节数组
                return new byte[0];
            }

            byte[] data = new byte[0];

            ClientLicense.Create(day, 3, Sn, new Action<byte[]>((bytes) => data = bytes));

            return data;

        }

        /// <summary>
        /// 生成服务器授权文件
        /// </summary>
        /// <param name="LicenseCount">授权最大客户端数量（-1为无限制）</param>
        /// <param name="LicenseDays">授权天数（-1为正式授权）</param>
        /// <param name="FilePrescription">文件时效</param>
        /// <returns></returns>
        public static bool CreateServerLicense(int LicenseCount, int LicenseDays, int FilePrescription)
        {
            XDocument xDoc = new XDocument();

            xDoc.Add(new XElement("ServerLicense",
                                  new XElement("Item",
                                                new XAttribute("Name", "Count"),                //授权许可客户端最大数量
                                                new XAttribute("Value", LicenseCount)
                                               ),
                                  new XElement("Item",
                                                new XAttribute("Name", "LicenseDays"),                    //授权许可使用天数
                                                new XAttribute("Value", LicenseDays)
                                               ),
                                  new XElement("Item",
                                                new XAttribute("Name", "LicenseDate"),           //授权日期，用于授权文件时效性检查
                                                new XAttribute("Value", DateTime.Now)
                                               ),
                                  new XElement("Item",
                                                new XAttribute("Name", "Prescription"),          //授权文件时效
                                                new XAttribute("Value", FilePrescription)
                                               )
                                   )
                     );

            try
            {
                Save(xDoc, string.Format(@"{0}\{1}", System.Environment.CurrentDirectory, CONST_LICENSE_FILENAME));
            }
            catch (Exception e)
            {
                throw e;
            }
            return true;

        }


        /// <summary>
        /// 许可加载
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static ServerLicense LoadLicense(string dir)
        {
            string path = string.Format(@"{0}\{1}", dir, CONST_LICENSE_FILENAME);

            if (!System.IO.File.Exists(path))
            {
                return null;
            }

            try
            {
                byte[] buff;
                using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    buff = new byte[fs.Length];

                    fs.Read(buff, 0, buff.Length);

                    fs.Close();
                }

                buff = Crypt.SchemeCrypt.Instance.Decrypt(buff);

                string xml = Encoding.UTF8.GetString(buff);

                XDocument xDoc = XDocument.Parse(xml);

                if (xDoc.Element("ServerLicense") == null) return null;

                int intPres = int.Parse(getData(xDoc, "Prescription"));

                if (intPres != -1)          //如果授权时效不等于-1，那么表示存在时效，需要比较许可生成时间，和当前PC时间，如果超过授权时效，则返回NULL
                {
                    DateTime dt = DateTime.Parse(getData(xDoc, "LicenseDate"));
                    if (DateTime.Now.Subtract(dt).Days >= intPres) return null;

                    xDoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == "Prescription").First().Attribute("Value").Value = "-1";           //修改授权时效

                    Save(xDoc, path);
                }

                return new ServerLicense(xDoc, dir);

            }
            catch { return null; }
        }


        /// <summary>
        /// 加密存储
        /// </summary>
        /// <param name="xDoc"></param>
        private static void Save(XDocument xDoc, string path)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(xDoc.ToString());

            buffer = Crypt.SchemeCrypt.Instance.Encrypt(buffer);

            using (System.IO.FileStream fs = new System.IO.FileStream(path, System.IO.FileMode.Create, System.IO.FileAccess.Write))
            {
                fs.Write(buffer, 0, buffer.Length);

                fs.Close();
            }
        }


        private static string getData(XDocument xdoc, string nameValue)
        {
            try
            {
                return xdoc.Descendants("Item").Where((xe) => xe.Attribute("Name").Value == nameValue).First().Attribute("Value").Value;
            }
            catch (Exception e)
            {
                throw e;
            }
        }



    }
}
